// 策略模式
let tween = {
  linear: (t, b, c, d) => c*t/d + b,
  easeIn: (t, b, c, d) => c*(t/=d) * t + b,
  strongEaseIn: (t, b, c, d) => c*(t/=d) * t^4 + b,
  strongEaseOut: (t, b, c, d) => c * ((t = t/d-1) * t^4 + 1) + b,
  sineaseIn: (t, b, c, d) => c * (t/=d) * t^2 + b,
  sineaseOut: (t, b, c, d) => c * ((t = t/d-1) * t^2 + 1) + b
}
class Animate {
  constructor(dom) {
    this.dom = dom // dom节点
    this.startTime = 0 // 动画开始时间
    this.startPos = 0 // dom起始位置
    this.endPos = 0 // dom目标位置
    this.propertyName = null // dom需改变的属性名
    this.easing = null // 缓动算法
    this.duration = null // 动画持续时间
  }
  start(propertyName, endPos, duration, easing) {
    this.startTime = +new Date()
    this.startPos = this.dom.getBoundingClientRect()[propertyName]
    this.propertyName = propertyName
    this.endPos = endPos
    this.duration = duration
    this.easing = tween[easing]

    let self = this
    // 启动定时器执行动画
    let timeId = setInterval(() => {
      // 动画已完成，清除定时器
      if(self.step() === false) {
        clearInterval(timeId)
      }
    }, 19)
  }
  step() {
    let t = +new Date()
    // 动画已结束，修正小球位置
    if(t >= this.startTime + this.duration) {
      // 更新小球的css属性
      this.update(this.endPos)
      return false
    }
    // 当前小球的位置
    let pos = this.easing(
      t-this.startTime,
      this.startPos,
      this.endPos-this.startPos,
      this.duration
    )
    // 更新小球的css属性
    this.update(pos)
  }
  update(pos) {
    this.dom.style[this.propertyName] = pos + 'px'
  }
}